﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MaintainabilityRules.cs" company="StyleCop for ReSharper Development Team">
//   Copyright (c) StyleCop for ReSharper Development Team. All rights reserved.
// </copyright>
// <summary>
//   Defines the MaintainabilityRules type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace StyleCop.For.ReSharper.CodeCleanup.Rules
{
    #region Using Directives

    using JetBrains.ReSharper.Psi.CSharp.Impl.Tree;
    using JetBrains.ReSharper.Psi.CSharp.Tree;
    using JetBrains.ReSharper.Psi.ExtensionsAPI;
    using JetBrains.ReSharper.Psi.ExtensionsAPI.Tree;
    using JetBrains.ReSharper.Psi.Tree;

    using StyleCop.For.ReSharper.CodeCleanup.Options;
    using StyleCop.For.ReSharper.Diagnostics;

    #endregion

    /// <summary>
    /// Maintainability rules.
    /// </summary>
    internal class MaintainabilityRules
    {
        #region Public Methods

        /// <summary>
        /// Remove parenthesis from node.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        public static void RemoveParenthesisFromNode(ITreeNode node)
        {
            var parenthesizedExpressionNode = node as IParenthesizedExpressionNode;
            if (parenthesizedExpressionNode != null)
            {
                var innerExpression = parenthesizedExpressionNode.ExpressionNode;

                if (innerExpression != null && node.Parent != null)
                {
                    var innerExpressionNodeType = (innerExpression as TreeElement).NodeType;

                    if (innerExpressionNodeType != ElementType.ADDITIVE_EXPRESSION && innerExpressionNodeType != ElementType.MULTIPLICATIVE_EXPRESSION &&
                        innerExpressionNodeType != ElementType.SHIFT_EXPRESSION && innerExpressionNodeType != ElementType.AS_EXPRESSION && innerExpressionNodeType != ElementType.ASSIGNMENT_EXPRESSION &&
                        innerExpressionNodeType != ElementType.CAST_EXPRESSION && innerExpressionNodeType != ElementType.CONDITIONAL_AND_EXPRESSION &&
                        innerExpressionNodeType != ElementType.CONDITIONAL_OR_EXPRESSION && innerExpressionNodeType != ElementType.CONDITIONAL_TERNARY_EXPRESSION &&
                        innerExpressionNodeType != ElementType.POSTFIX_OPERATOR_EXPRESSION && innerExpressionNodeType != ElementType.PREFIX_OPERATOR_EXPRESSION &&
                        innerExpressionNodeType != ElementType.IS_EXPRESSION && innerExpressionNodeType != ElementType.LAMBDA_EXPRESSION &&
                        innerExpressionNodeType != ElementType.BITWISE_AND_EXPRESSION && innerExpressionNodeType != ElementType.BITWISE_INCLUSIVE_OR_EXPRESSION &&
                        innerExpressionNodeType != ElementType.BITWISE_EXCLUSIVE_OR_EXPRESSION && innerExpressionNodeType != ElementType.OBJECT_CREATION_EXPRESSION &&
                        innerExpressionNodeType != ElementType.ARRAY_CREATION_EXPRESSION && innerExpressionNodeType != ElementType.NULL_COALESCING_EXPRESSION &&
                        innerExpressionNodeType != ElementType.QUERY_EXPRESSION && innerExpressionNodeType != ElementType.RELATIONAL_EXPRESSION &&
                        innerExpressionNodeType != ElementType.UNARY_OPERATOR_EXPRESSION && innerExpressionNodeType != ElementType.EQUALITY_EXPRESSION)
                    {
                        LowLevelModificationUtil.ReplaceChildRange(node, node, new ITreeNode[] { innerExpression });
                        return;
                    }

                    if ((!(node.Parent is IExpression)) || node.Parent is IVariableDeclaration)
                    {
                        LowLevelModificationUtil.ReplaceChildRange(node, node, new ITreeNode[] { innerExpression });
                        return;
                    }

                    var parent = node.Parent as IAssignmentExpression;

                    if (parent != null && parent.Source == node)
                    {
                        LowLevelModificationUtil.ReplaceChildRange(node, node, new ITreeNode[] { innerExpression });
                        return;
                    }
                }
            }
        }

        /// <summary>
        /// Remove unnecessary parenthesis from statements.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        public static void RemoveUnnecessaryParenthesisFromStatements(ITreeNode node)
        {
            for (var currentNode = node; currentNode != null; currentNode = currentNode.NextSibling)
            {
                RemoveParenthesisFromNode(currentNode);

                if (currentNode.FirstChild != null)
                {
                    RemoveUnnecessaryParenthesisFromStatements(currentNode.FirstChild);
                }
            }
        }

        /// <summary>
        /// Execute.
        /// </summary>
        /// <param name="options">
        /// The options.
        /// </param>
        /// <param name="file">
        /// The file.
        /// </param>
        public void Execute(MaintainabilityOptions options, ICSharpFile file)
        {
            StyleCopTrace.In(options, file);

            var statementMustNotUseUnnecessaryParenthesis = options.SA1119StatementMustNotUseUnnecessaryParenthesis;

            if (statementMustNotUseUnnecessaryParenthesis)
            {
                RemoveUnnecessaryParenthesisFromStatements(file.ToTreeNode().FirstChild);
            }

            StyleCopTrace.Out();
        }

        #endregion
    }
}